home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / Other Langs / Tickle-4.0 (tcl) / tcl / src / tclGlob.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-08  |  17.7 KB  |  713 lines  |  [TEXT/MPS ]

  1. #ifdef MPW
  2. #    pragma segment TCL_GLOB
  3. #endif
  4.  
  5. /* 
  6.  * tclGlob.c --
  7.  *
  8.  *    This file provides procedures and commands for file name
  9.  *    manipulation, such as tilde expansion and globbing.
  10.  *
  11.  * Copyright (c) 1990-1993 The Regents of the University of California.
  12.  * All rights reserved.
  13.  *
  14.  * Permission is hereby granted, without written agreement and without
  15.  * license or royalty fees, to use, copy, modify, and distribute this
  16.  * software and its documentation for any purpose, provided that the
  17.  * above copyright notice and the following two paragraphs appear in
  18.  * all copies of this software.
  19.  * 
  20.  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
  21.  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
  22.  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
  23.  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24.  *
  25.  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
  26.  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  27.  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  28.  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
  29.  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  30.  */
  31.  
  32. #ifndef lint
  33. static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclGlob.c,v 1.35 93/08/28 15:57:51 ouster Exp $ SPRITE (Berkeley)";
  34. #endif /* not lint */
  35.  
  36. #include "tclInt.h"
  37. #include "tclUnix.h"
  38.  
  39. #ifdef macintosh
  40. #    include <files.h>
  41. #    include <errors.h>
  42. #ifndef FALSE
  43. #    define FALSE    0
  44. #endif
  45. //#    include "stat.h"
  46. #endif
  47.  
  48. /*
  49.  * The structure below is used to keep track of a globbing result
  50.  * being built up (i.e. a partial list of file names).  The list
  51.  * grows dynamically to be as big as needed.
  52.  */
  53.  
  54. typedef struct {
  55.     char *result;        /* Pointer to result area. */
  56.     int totalSpace;        /* Total number of characters allocated
  57.                  * for result. */
  58.     int spaceUsed;        /* Number of characters currently in use
  59.                  * to hold the partial result (not including
  60.                  * the terminating NULL). */
  61.     int dynamic;        /* 0 means result is static space, 1 means
  62.                  * it's dynamic. */
  63. } GlobResult;
  64.  
  65. static int        _glob_debug_level = 0;
  66. static int        _glob_show_invisibles = 0;
  67.  
  68. static int        _glob_show_type = 0;
  69. static int        _glob_show_creator = 0;
  70. static ResType    _glob_type;
  71. static ResType    _glob_creator;
  72.  
  73. /*
  74.  * Declarations for procedures local to this file:
  75.  */
  76.  
  77. static int        DoGlob _ANSI_ARGS_((Tcl_Interp *interp, char *dir,
  78.                 char *rem));
  79.  
  80. /*
  81.  *----------------------------------------------------------------------
  82.  *
  83.  * DoGlob --
  84.  *
  85.  *    This recursive procedure forms the heart of the globbing
  86.  *    code.  It performs a depth-first traversal of the tree
  87.  *    given by the path name to be globbed.
  88.  *
  89.  * Results:
  90.  *    The return value is a standard Tcl result indicating whether
  91.  *    an error occurred in globbing.  After a normal return the
  92.  *    result in interp will be set to hold all of the file names
  93.  *    given by the dir and rem arguments.  After an error the
  94.  *    result in interp will hold an error message.
  95.  *
  96.  * Side effects:
  97.  *    None.
  98.  *
  99.  *----------------------------------------------------------------------
  100.  */
  101.  
  102. static int
  103. DoGlob(interp, dir, rem)
  104.     Tcl_Interp    *interp;    /* Interpreter to use for error
  105.                             ** reporting (e.g. unmatched brace).
  106.                             */
  107.     char        *dir;        /* Name of a directory at which to
  108.                             ** start glob expansion.  This name
  109.                             ** is fixed: it doesn't contain any
  110.                             ** globbing chars.
  111.                             */
  112.     char        *rem;        /* Path to glob-expand. */
  113.     {
  114.     /*
  115.     ** When this procedure is entered, the name to be globbed may
  116.     ** already have been partly expanded by ancestor invocations of
  117.     ** DoGlob.  The part that's already been expanded is in "dir"
  118.     ** (this may initially be empty), and the part still to expand
  119.     ** is in "rem".  This procedure expands "rem" one level, making
  120.     ** recursive calls to itself if there's still more stuff left
  121.     ** in the remainder.
  122.     */
  123.  
  124.     Tcl_DString        newName;    /* Holds new name consisting of
  125.                                 ** dir plus the first part of rem.
  126.                                 */
  127.     register char    *p;
  128.     register char    c;
  129.     char            *openBrace, *closeBrace, *name;
  130.     int                gotSpecial, baseLength;
  131.     int                result = TCL_OK, myerr, match, scan_volumes = 0;
  132.     struct stat        statBuf;
  133.     char            mac_name[256], *dirName;
  134.  
  135.     /*
  136.     ** Make sure that the directory part of the name really is a
  137.     ** directory.  If the directory name is "", use the name "."
  138.     ** instead, because some UNIX systems don't treat "" like "."
  139.     ** automatically. Keep the "" for use in generating file names,
  140.     ** otherwise "glob foo.c" would return "./foo.c".
  141.     */
  142.  
  143. //    Feedback("GLOB: dir <%.64s> rem <%.64s> ", dir, rem);
  144.  
  145.     if (*dir == '\0')
  146.         {
  147. #ifdef macintosh
  148.         if ( strchr(rem, ':') != NULL )
  149.             scan_volumes = 1;
  150.         
  151.         dirName = ":";
  152. #else
  153.         dirName = ".";
  154. #endif
  155.         }
  156. #ifdef macintosh
  157.     else if ( *dir != ':' && strchr(dir, ':') == NULL )
  158.         {
  159. //Feedback("GLOB: SPECIAL Volume case, adding colon ");
  160.         strcpy(mac_name, dir);
  161.         strcat(mac_name, ":");
  162.         dirName = mac_name;
  163.         }
  164. #endif
  165.     else
  166.         {
  167.         dirName = dir;
  168.         }
  169.     
  170.     if ((stat(dirName, &statBuf) != 0) || !S_ISDIR(statBuf.st_mode))
  171.         {
  172.         Tcl_ResetResult(interp);
  173.         Tcl_AppendResult(interp, "could not locate directory \"",
  174.                             dirName, "\" ", NULL);
  175.         return TCL_ERROR;
  176.         /*return TCL_OK;*/
  177.         }
  178.     
  179. //Feedback("GLOB: STAT of dir <%.64s> OK ", dirName);
  180.     Tcl_DStringInit(&newName);
  181.  
  182.     /*
  183.     ** First, find the end of the next element in rem, checking
  184.     ** along the way for special globbing characters.
  185.     */
  186.  
  187.     gotSpecial = 0;
  188.     openBrace = closeBrace = NULL;
  189.     for ( p = rem ; ; p++ )
  190.         {
  191.         c = *p;
  192. #ifdef macintosh
  193.         if ((c == '\0') || ((openBrace == NULL) && (c == ':')))
  194. #else
  195.         if ((c == '\0') || ((openBrace == NULL) && (c == '/')))
  196. #endif
  197.             {
  198.             break;
  199.             }
  200.         if ((c == '{') && (openBrace == NULL))
  201.             {
  202.             openBrace = p;
  203.             }
  204.         if ((c == '}') && (openBrace != NULL) && (closeBrace == NULL))
  205.             {
  206.             closeBrace = p;
  207.             }
  208.         if ((c == '*') || (c == '[') || (c == '\\') || (c == '?'))
  209.             {
  210.             gotSpecial = 1;
  211.             }
  212.         }
  213.  
  214.     /*
  215.     ** If there is an open brace in the argument, then make a recursive
  216.     ** call for each element between the braces.  In this case, the
  217.     ** recursive call to DoGlob uses the same "dir" that we got.
  218.     ** If there are several brace-pairs in a single name, we just handle
  219.     ** one here, and the others will be handled in recursive calls.
  220.     */
  221.  
  222.     if (openBrace != NULL)
  223.         {
  224.         char *element;
  225.  
  226.         if (closeBrace == NULL)
  227.             {
  228.             Tcl_ResetResult(interp);
  229.             interp->result = "unmatched open-brace in file name";
  230.             result = TCL_ERROR;
  231.             goto done;
  232.             }
  233.             
  234.         Tcl_DStringAppend(&newName, rem, openBrace-rem);
  235.         baseLength = newName.length;
  236.         p = openBrace;
  237.         
  238.         for ( p = openBrace ; *p != '}' ; )
  239.             {
  240.             element = p+1;
  241.             for ( p = element ; ((*p != '}') && (*p != ',')) ; p++ )
  242.                 {
  243.                 /* Empty loop body. */
  244.                 }
  245.             Tcl_DStringAppend(&newName, element, p-element);
  246.             Tcl_DStringAppend(&newName, closeBrace+1, -1);
  247.             result = DoGlob(interp, dir, newName.string);
  248.             if (result != TCL_OK)
  249.                 {
  250.                 goto done;
  251.                 }
  252.             newName.length = baseLength;
  253.             }
  254.         
  255.         goto done;
  256.         }
  257.  
  258.     /*
  259.     ** Start building up the next-level name with dir plus a slash if
  260.     ** needed to separate it from the next file name.
  261.     */
  262.  
  263.     Tcl_DStringAppend(&newName, dir, -1);
  264. #ifdef macintosh
  265.     if ((dir[0] != 0) && (newName.string[newName.length-1] != ':'))
  266.         {
  267.         Tcl_DStringAppend(&newName, ":", 1);
  268.         }
  269. #else
  270.     if ((dir[0] != 0) && (newName.string[newName.length-1] != '/'))
  271.         {
  272.         Tcl_DStringAppend(&newName, "/", 1);
  273.         }
  274. #endif
  275.     baseLength = newName.length;
  276.  
  277. //Feedback("JUST_SPEC: newName '%.*s' ", newName.length, newName.string);
  278.  
  279.     /*
  280.     ** If there were any pattern-matching characters, then scan through
  281.     ** the directory to find all the matching names.
  282.     */
  283.  
  284.     if (gotSpecial)
  285.         {
  286.         char            *dir_ptr = dir;    /* Use for > 256 chars */
  287.         int                index, vrefnum;
  288.         long            dirid;
  289.         char            savedChar;
  290.         CInfoPBRec        cpb;
  291.         HParamBlockRec    vpb;
  292.  
  293.         result = TCL_OK;
  294.         savedChar = *p;
  295.         *p = 0;
  296.  
  297.         if ( scan_volumes )
  298.             {
  299.     //Feedback("GLOB: SCAN: VOLUMES CASE D '%s' R '%s' ", dir, rem);
  300.             }
  301.         else if ( S_ISDIR(statBuf.st_mode) )
  302.             {
  303.             vrefnum = statBuf.st_dev;
  304.             dirid = statBuf.st_ino;
  305.             }
  306.         else
  307.             {
  308.             /* RELATIVE */
  309.             WDPBRec    wpb;
  310.             Str32    volname;
  311.             
  312.             wpb.ioCompletion = 0;
  313.             wpb.ioNamePtr = volname;
  314.             PBHGetVol(&wpb, FALSE);
  315.             
  316.             vrefnum = wpb.ioWDVRefNum;
  317.             dirid = wpb.ioWDDirID;
  318.             }
  319.          
  320. //Feedback("GLOB: SCAN: vRef %d dirID %ld rem '%s' ",
  321. //                vrefnum, dirid, rem );
  322.         
  323.         for ( index=1 ; ; index++ )
  324.             {
  325. #ifdef ROTATE_THE_CURSOR
  326.     RotateCursor( 8 * index );
  327. #endif
  328.  
  329.             if ( scan_volumes )
  330.                 {
  331.                 mac_name[0] = '\0';
  332.                 vpb.volumeParam.ioCompletion = 0;
  333.                 vpb.volumeParam.ioVolIndex = index;
  334.                 vpb.volumeParam.ioNamePtr = (unsigned char *)mac_name;
  335.                 vpb.volumeParam.ioVRefNum = 0;
  336.                 result = PBHGetVInfo( &vpb, FALSE );
  337.     //Feedback( "GLOB: SCAN: GetVInfo(%d) = %d, '%.*s' ",
  338.     //        index, result, mac_name[0], &mac_name[1] );
  339.                 if (result == nsvErr)
  340.                     {
  341.                     result = TCL_OK;
  342.                     break;
  343.                     }
  344.                     
  345.                 p2cstr(mac_name);
  346.                 }
  347.             else
  348.                 {
  349.                 mac_name[0] = '\0';
  350.                 cpb.hFileInfo.ioCompletion = 0;
  351.                 cpb.hFileInfo.ioVRefNum = vrefnum;
  352.                 cpb.hFileInfo.ioNamePtr = (unsigned char *)mac_name;
  353.                 cpb.hFileInfo.ioFDirIndex = index;
  354.                 cpb.hFileInfo.ioDirID = dirid;
  355.                 result = PBGetCatInfo(&cpb, FALSE);
  356.     //Feedback("GLOB: INDEX-%03d = %d, <%.*s> [%ld]",
  357.     //        index, result, mac_name[0], &mac_name[1], dirid);
  358.                 if (result == fnfErr)
  359.                     {
  360.                     result = TCL_OK;
  361.                     break;
  362.                     }
  363.     
  364.                 if (! _glob_show_invisibles)
  365.                     if ((cpb.hFileInfo.ioFlFndrInfo.fdFlags & fInvisible) != 0)
  366.                         {
  367.     //Feedback("GLOB: SKIP INVISIBLE <%.*s> ", mac_name[0], &mac_name[1]);
  368.                         continue;
  369.                         }
  370.                 
  371.                 if (_glob_show_type)
  372.                     if (cpb.hFileInfo.ioFlFndrInfo.fdType != _glob_type)
  373.                         {
  374.     //Feedback("GLOB: SKIP !TYPE '%4.4s' <%.*s> ",
  375.     //        &cpb.hFileInfo.ioFlFndrInfo.fdType, mac_name[0], &mac_name[1]);
  376.                         continue;
  377.                         }
  378.                 
  379.                 if (_glob_show_creator)
  380.                     if (cpb.hFileInfo.ioFlFndrInfo.fdCreator != _glob_creator)
  381.                         {
  382.     //Feedback("GLOB: SKIP !CREATOR '%4.4s' <%.*s> ",
  383.     //            &cpb.hFileInfo.ioFlFndrInfo.fdCreator, mac_name[0], &mac_name[1]);
  384.                         continue;
  385.                         }
  386.                 
  387.                 p2cstr(mac_name);
  388.                 
  389.                 /*
  390.                 ** Don't match names starting with "." unless the "." is
  391.                 ** present in the pattern.
  392.                 */
  393.                 if ((*mac_name == '.') && (*rem != '.'))
  394.                     {
  395.     //Feedback("GLOB: SKIP DOT FILE <%.*s> ", mac_name[0], &mac_name[1]);
  396.                     continue;
  397.                     }
  398.                 if ((*mac_name == '•') && (*rem != '•'))
  399.                     {
  400.     //Feedback("GLOB: SKIP SPOT FILE <%.*s> ", mac_name[0], &mac_name[1]);
  401.                     continue;
  402.                     }
  403.                 } /* ! scan_volumes */
  404.             
  405.             match = Tcl_StringMatchNoCase( (char *)mac_name, rem );
  406. //Feedback( "GLOB: SCAN: %s Name '%s' Rem '%s' ",
  407. //                (match ? "MATCH" : "NO MATCH"), mac_name, rem );
  408.  
  409.             if ( match )
  410.                 {
  411. //Feedback("GLOB: SCAN: MATCH '%s' ", mac_name);
  412.                 newName.length = baseLength;
  413.                 Tcl_DStringAppend(&newName, mac_name, -1);
  414.                 
  415.                 if (savedChar == '\0')
  416.                     {
  417.                     Tcl_AppendElement(interp, newName.string);
  418.                     }
  419.                 else if ( scan_volumes ||
  420.                             (cpb.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
  421.                     {
  422.                     result = DoGlob(interp, newName.string, p + 1);
  423.                     
  424.                     if (result != TCL_OK)
  425.                         break;
  426.                     }
  427.                 }
  428.             else
  429.                 {
  430. //Feedback("GLOB: SCAN: NO MATCH '%s' ", mac_name);
  431.                 }
  432.             }
  433.         
  434.         *p = savedChar;
  435.         goto done;
  436.         }
  437.  
  438.     /*
  439.     ** The current element is a simple one with no fancy features.  Add
  440.     ** it to the new name.  If there are more elements still to come,
  441.     ** then recurse to process them.
  442.     */
  443. #ifdef macintosh
  444.     if (*p == ':')
  445.         ++p;
  446. #endif
  447.         
  448.     Tcl_DStringAppend(&newName, rem, p-rem);
  449.     if ( *p != 0 )
  450.         {
  451. //Feedback( "RECURSING... '%s' '%s'", newName.string, p );
  452.         result = DoGlob( interp, newName.string, p );
  453.         goto done;
  454.         }
  455.  
  456.     /*
  457.     ** There are no more elements in the pattern.  Check to be sure the
  458.     ** file actually exists, then add its name to the list being formed
  459.     ** in interp-result.
  460.     */
  461.  
  462. //Feedback( "APPENDING... '%s'", newName.string );
  463.     name = newName.string;
  464.     if (*name == 0)
  465.         {
  466. #ifdef macintosh
  467.         name = ":";
  468. #else
  469.         name = ".";
  470. #endif
  471.         }
  472.     
  473.     myerr = access(name, F_OK);
  474. //Feedback("access(%s, F_OK) = %d, errno=%d ", name, myerr, errno);
  475.     if (myerr != 0)
  476.         {
  477.         goto done;
  478.         }
  479.     
  480.     Tcl_AppendElement(interp, name);
  481.  
  482. done:
  483.     Tcl_DStringFree(&newName);
  484.     return result;
  485.     }
  486.  
  487. /*
  488.  *----------------------------------------------------------------------
  489.  *
  490.  * Tcl_TildeSubst --
  491.  *
  492.  *    Given a name starting with a tilde, produce a name where
  493.  *    the tilde and following characters have been replaced by
  494.  *    the home directory location for the named user.
  495.  *
  496.  * Results:
  497.  *    The result is a pointer to a static string containing
  498.  *    the new name.  If there was an error in processing the
  499.  *    tilde, then an error message is left in interp->result
  500.  *    and the return value is NULL.  The result may be stored
  501.  *    in bufferPtr; the caller must call Tcl_DStringFree(bufferPtr)
  502.  *    to free the name.
  503.  *
  504.  * Side effects:
  505.  *    Information may be left in bufferPtr.
  506.  *
  507.  *----------------------------------------------------------------------
  508.  */
  509.  
  510. char *
  511. Tcl_TildeSubst(interp, name, bufferPtr)
  512.     Tcl_Interp *interp;        /* Interpreter in which to store error
  513.                  * message (if necessary). */
  514.     char *name;            /* File name, which may begin with "~/"
  515.                  * (to indicate current user's home directory)
  516.                  * or "~<user>/" (to indicate any user's
  517.                  * home directory). */
  518.     Tcl_DString *bufferPtr;    /* May be used to hold result.  Must not hold
  519.                  * anything at the time of the call, and need
  520.                  * not even be initialized. */
  521.     {
  522.     char *dir;
  523.     register char *p;
  524.     extern char *tcl_getenv();
  525.  
  526.     Tcl_DStringInit(bufferPtr);
  527.     if (name[0] != '~')
  528.         {
  529.         return name;
  530.         }
  531.  
  532.     if ( (name[1] == ':') || (name[1] == '\0') )
  533.         {
  534.         dir = tcl_getenv("HOME");
  535.         if (dir == NULL)
  536.             {
  537.             Tcl_ResetResult(interp);
  538.             Tcl_AppendResult(interp, "couldn't find HOME environment ",
  539.                 "variable to expand \"", name, "\"", (char *) NULL);
  540.             return NULL;
  541.             }
  542.         Tcl_DStringAppend(bufferPtr, dir, -1);
  543.         if ( bufferPtr->string[ bufferPtr->length - 1 ] != ':' )
  544.             Tcl_DStringAppend( bufferPtr, ":", -1 );
  545.         if (name[1] != '\0')
  546.             Tcl_DStringAppend( bufferPtr, name + 2, -1 );
  547.         }
  548.     else
  549.         {
  550.         dir = tcl_getenv("APPDIR");
  551.         if (dir == NULL)
  552.             {
  553.             Tcl_ResetResult(interp);
  554.             Tcl_AppendResult(interp, "couldn't find APPDIR environment ",
  555.                 "variable to expand \"", name, "\"", (char *) NULL);
  556.             return NULL;
  557.             }
  558.         for ( p = &name[1] ; (*p != 0) && (*p != ':') ; ++p )
  559.             {
  560.             /* Null body;  just find end of name. */
  561.             }
  562.         Tcl_DStringAppend(bufferPtr, dir, -1);
  563.         if ( bufferPtr->string[ bufferPtr->length - 1 ] != ':' )
  564.             Tcl_DStringAppend( bufferPtr, ":", -1 );
  565.         Tcl_DStringAppend( bufferPtr, name + 1, p - (name + 1) );
  566.         if (*p != '\0')
  567.             Tcl_DStringAppend( bufferPtr, p + 1, -1 );
  568.         }
  569.     
  570.     return bufferPtr->string;
  571.     }
  572.  
  573. /*
  574.  *----------------------------------------------------------------------
  575.  *
  576.  * Tcl_GlobCmd --
  577.  *
  578.  *    This procedure is invoked to process the "glob" Tcl command.
  579.  *    See the user documentation for details on what it does.
  580.  *
  581.  * Results:
  582.  *    A standard Tcl result.
  583.  *
  584.  * Side effects:
  585.  *    See the user documentation.
  586.  *
  587.  *----------------------------------------------------------------------
  588.  */
  589.  
  590.     /* ARGSUSED */
  591. int
  592. Tcl_GlobCmd(client, interp, argc, argv)
  593.     ClientData    client;        /* Not used. */
  594.     Tcl_Interp    *interp;    /* Current interpreter. */
  595.     int            argc;        /* Number of arguments. */
  596.     char        **argv;        /* Argument strings. */
  597.     {
  598.     int i, result, noComplain, firstArg;
  599. #pragma unused (client)
  600.  
  601.     _glob_show_type = 0;
  602.     _glob_show_creator = 0;
  603.     _glob_show_invisibles = 0;
  604.  
  605.     if (argc < 2)
  606.         {
  607. notEnoughArgs:
  608.         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
  609.                             " ?switches? name ?name ...?\"", (char *) NULL);
  610.         return TCL_ERROR;
  611.         }
  612.     noComplain = 0;
  613.     for (    firstArg = 1
  614.         ;    (firstArg < argc) && (argv[firstArg][0] == '-')
  615.         ;    firstArg++
  616.         )
  617.         {
  618.         if (strcmp(argv[firstArg], "-nocomplain") == 0)
  619.             {
  620.             noComplain = 1;
  621.             }
  622.         else if (strcmp(argv[firstArg], "--") == 0)
  623.             {
  624.             firstArg++;
  625.             break;
  626.             }
  627.         else if (strcmp(argv[firstArg], "-i") == 0)
  628.             {
  629.             _glob_show_invisibles = 1;
  630.             }
  631.         else if (strcmp(argv[firstArg], "-c") == 0)
  632.             {
  633.             _glob_show_creator = 1;
  634.             sprintf((char *)&_glob_creator, "%-4.4s", argv[++firstArg]);
  635.             }
  636.         else if (strcmp(argv[firstArg], "-t") == 0)
  637.             {
  638.             _glob_show_type = 1;
  639.             sprintf((char *)&_glob_type, "%-4.4s", argv[++firstArg]);
  640.             }
  641.         else
  642.             {
  643.             Tcl_AppendResult(interp, "bad switch \"", argv[firstArg],
  644.                                 "\": must be -nocomplain or --", (char *) NULL);
  645.             return TCL_ERROR;
  646.             }
  647.         }
  648.     if (firstArg >= argc)
  649.         {
  650.         goto notEnoughArgs;
  651.         }
  652.     
  653.     for (i = firstArg; i < argc; i++)
  654.         {
  655.         char *thisName;
  656.         Tcl_DString buffer;
  657.         
  658.         thisName = Tcl_TildeSubst(interp, argv[i], &buffer);
  659.         if (thisName == NULL)
  660.             {
  661.             return TCL_ERROR;
  662.             }
  663.         
  664. #ifndef macintosh
  665.         if (*thisName == '/')
  666.             {
  667.             if (thisName[1] == '/')
  668.                 {
  669.                 /*
  670.                 * This is a special hack for systems like those from Apollo
  671.                 * where there is a super-root at "//":  need to treat the
  672.                 * double-slash as a single name.
  673.                 */
  674.                 result = DoGlob(interp, "//", thisName+2);
  675.                 }
  676.             else
  677.                 {
  678.                 result = DoGlob(interp, "/", thisName+1);
  679.                 }
  680.             }
  681.         else
  682.             {
  683. #endif
  684.             result = DoGlob(interp, "", thisName);
  685. #ifndef macintosh
  686.             }
  687. #endif
  688.         
  689.         Tcl_DStringFree(&buffer);
  690.         if (result != TCL_OK)
  691.             {
  692.             return result;
  693.             }
  694.         }
  695.     
  696.     if ((*interp->result == 0) && !noComplain)
  697.         {
  698.         char *sep = "";
  699.         
  700.         Tcl_AppendResult(interp, "no files matched glob pattern",
  701.                             (argc == 2) ? " \"" : "s \"", (char *) NULL);
  702.         for (i = firstArg; i < argc; i++)
  703.             {
  704.             Tcl_AppendResult(interp, sep, argv[i], (char *) NULL);
  705.             sep = " ";
  706.             }
  707.         Tcl_AppendResult(interp, "\"", (char *) NULL);
  708.         return TCL_ERROR;
  709.         }
  710.     
  711.     return TCL_OK;
  712.     }
  713.